﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using Pipes.Queries.MetaData;

namespace Pipes.Queries.Provider.Wmi
{
  public class WmiProvider : IProvider
  {
    private Dictionary<string, RecordSet> _tables = new Dictionary<string, RecordSet>();
    private Dictionary<CimType, IDataType> _types = new Dictionary<CimType, IDataType>();
    
    public WmiProvider()
    {

    }

    public void Connect()
    {
      var wqlQuery = new WqlObjectQuery("SELECT * FROM meta_class"); //  WHERE __Class = 'Win32_LogicalDisk' SELECT * FROM Win32_LogicalDisk
      var searcher = new ManagementObjectSearcher(wqlQuery);
      RecordSet table;
      Column col;

      foreach (ManagementObject obj in searcher.Get())
      {
        table = new RecordSet();
        table.Name = obj.Path.ClassName;
        foreach (var prop in obj.Properties)
        {
          col = new Column();
          col.Name = prop.Name;
          col.Type = GetDataType(prop.Type);
        }
      }
    }

    private IDataType GetDataType(CimType type)
    {
      IDataType result = null;
      if (!_types.TryGetValue(type, out result))
      {
        switch(type)
        {
          case CimType.Boolean:
            result = new BooleanType();
            break;
          case CimType.Char16:
            result = new NumericType() { StorageBits = 16 };
            break;
          case CimType.DateTime:
            result = new DateType() { Parts = DateType.DateParts.timestamp };
            break;
          case CimType.Real32:
            result = new NumericType() { StorageBits = 32, Type = NumericType.NumericTypes.@float };
            break;
          case CimType.Real64:
            result = new NumericType() { StorageBits = 64, Type = NumericType.NumericTypes.@float };
            break;
          case CimType.SInt16:
            result = new NumericType() { StorageBits = 16, Type = NumericType.NumericTypes.signed_integer };
            break;
          case CimType.SInt32:
            result = new NumericType() { StorageBits = 32, Type = NumericType.NumericTypes.signed_integer };
            break;
          case CimType.SInt64:
            result = new NumericType() { StorageBits = 64, Type = NumericType.NumericTypes.signed_integer };
            break;
          case CimType.SInt8:
            result = new NumericType() { StorageBits = 8, Type = NumericType.NumericTypes.signed_integer };
            break;
          case CimType.String:
            result = new CharacterType() { SeparateStorage = false, VariableLength = true, Unicode = true, StorageChars = int.MaxValue };
            break;
          case CimType.UInt16:
            result = new NumericType() { StorageBits = 16, Type = NumericType.NumericTypes.unsigned_integer };
            break;
          case CimType.UInt32:
            result = new NumericType() { StorageBits = 32, Type = NumericType.NumericTypes.unsigned_integer };
            break;
          case CimType.UInt64:
            result = new NumericType() { StorageBits = 64, Type = NumericType.NumericTypes.unsigned_integer };
            break;
          case CimType.UInt8:
            result = new NumericType() { StorageBits = 8, Type = NumericType.NumericTypes.unsigned_integer };
            break;
        }
        result.Name = type.ToString();
        _types[type] = result;
      }
      return result;
    }

    public System.Data.DataSet ExecuteQuery(Model.Query.Script query)
    {
      throw new NotImplementedException();
    }

    public IMetaObject GetMetaData(IEnumerable<string> path)
    {
      var i = 0;
      IMetaObject result = null;
      foreach (var part in path)
      {
        switch(i)
        {
          case 0:
            if (!Utils.TryGetValue(_tables, part, out result)) return null;
            break;
          case 1:
            if (!Utils.TryGetValue(((RecordSet)result).Columns, part, out result)) return null;
            break;
        }
        i++;
      }
      return result;
    }

    
  }
}
